📝 Резюме · 📄 Оригинал (1.2 KB)
https://t.me/Python_libr/3362
Функция exec() в Python, выполняет блок кода
Источник: https://t.me/Python_libr/3362
Что такое exec()?
exec() — встроенная функция для динамического выполнения кода Python во время работы программы. Отличается от eval() тем, что может выполнять полные блоки кода (циклы, функции, классы), а не только выражения.
Синтаксис и аргументы
exec(object, globals=None, locals=None)
- object: строка, объект байт-кода или объект файла с Python кодом
- globals: словарь для глобального пространства имён (опционально)
- locals: словарь для локального пространства имён (опционально)
- Возвращаемое значение: всегда
None
Примеры: строковый код
# Простое выполнение
code = """
x = 10
y = 20
result = x + y
print(f'Результат: {result}')
"""
exec(code)
# Выведет: Результат: 30
# Выполнение с несколькими операторами
code = """
for i in range(3):
print(f'Итерация {i}')
"""
exec(code)
# Выведет:
# Итерация 0
# Итерация 1
# Итерация 2
Использование глобального и локального пространств
# Создаём собственные пространства имён
globals_dict = {'x': 5, 'y': 10}
locals_dict = {}
code = """
z = x + y
result = z * 2
"""
exec(code, globals_dict, locals_dict)
print(locals_dict)
# {'result': 30}
print(globals_dict['z'])
# 30
Определение функций и классов
# Определение функции динамически
code = """
def greeting(name):
return f'Привет, {name}!'
class Calculator:
def add(self, a, b):
return a + b
"""
namespace = {}
exec(code, namespace)
# Используем определённую функцию
greet_func = namespace['greeting']
print(greet_func('Мария')) # Привет, Мария!
# Используем определённый класс
Calculator = namespace['Calculator']
calc = Calculator()
print(calc.add(5, 3)) # 8
Компиляция кода перед выполнением
# compile() преобразует код в объект для повторного выполнения
code_str = """
total = 0
for i in range(1, 6):
total += i
print(f'Сумма: {total}')
"""
# Компилируем один раз
compiled_code = compile(code_str, '<string>', 'exec')
# Выполняем скомпилированный код несколько раз
exec(compiled_code) # Сумма: 15
exec(compiled_code) # Сумма: 15
# Это быстрее, чем выполнять строку несколько раз
Практический пример: интерпретатор выражений
def simple_calculator(expression_list):
"""Выполняет список выражений"""
namespace = {}
for expr in expression_list:
try:
code = f"{expr}"
exec(code, namespace)
# Выводим локальные переменные
if 'result' in namespace:
print(f"{expr} => {namespace['result']}")
except Exception as e:
print(f"Ошибка: {e}")
return namespace
# Использование
expressions = [
"x = 10",
"y = 20",
"result = x + y",
"result = result * 2"
]
final_vars = simple_calculator(expressions)
print(final_vars)
# {'x': 10, 'y': 20, 'result': 60}
Диаграмма выполнения
graph LR
A["Строка кода<br/>или compile()"] --> B{"exec()<br/>функция"}
B --> C["Парсинг<br/>синтаксиса"]
C --> D["Компиляция<br/>в bytecode"]
D --> E["Выполнение<br/>в VM"]
E --> F["Возврат None"]
Отличие exec() от eval()
# eval() - работает только с выражениями
result = eval("2 + 3")
print(result) # 5
# eval с ошибкой - не может выполнить блок кода
try:
eval("x = 5") # SyntaxError!
except SyntaxError as e:
print(f"eval не поддерживает присваивание: {e}")
# exec() - работает с полными блоками
exec("x = 5")
# Работает без проблем
# exec() не возвращает значение
result = exec("2 + 3")
print(result) # None
# Нужно явно получить переменную
namespace = {}
exec("result = 2 + 3", namespace)
print(namespace['result']) # 5
Опасности и безопасность
# ОПАСНО: выполнять пользовательский код без проверки
user_input = "__import__('os').system('rm -rf /')"
# exec(user_input) # Не делайте так!
# БЕЗОПАСНО: ограничить доступные функции
safe_dict = {
'__builtins__': {
'print': print,
'len': len,
'range': range,
'str': str,
'int': int
}
}
# Пользователь может использовать только эти функции
user_code = "print(sum(range(10)))"
exec(user_code, safe_dict) # print: 45
# Опасные операции недоступны
try:
dangerous = "__import__('os')"
exec(dangerous, safe_dict)
except:
print("__import__ недоступен - защита работает!")
Лучшие практики
- Избегайте exec() если возможно — обычно есть лучшее решение
- Никогда не выполняйте пользовательский код без строгой валидации
- Используйте ограниченное пространство имён для безопасности
- Документируйте динамический код — это сложнее для отладки
- Кешируйте скомпилированный код если выполняете его много раз
- Обрабатывайте исключения — синтаксические ошибки приведут к сбоям